/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package zombiedefense.sprites;

import zombiedefense.framework.GameObject;
import zombiedefense.util.MathEx;
import zombiedefense.map.TileMap;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import zombiedefense.framework.EffectManager;
import zombiedefense.map.PathFinder;
import zombiedefense.map.Raycaster;
import zombiedefense.util.Vector2D;

/**
 * Defines a dynamic animation.
 * @author Laptop2010
 */
public abstract class Sprite implements Cloneable,GameObject{

    protected Animation[] anims;
    protected Animation animation;
    
    protected Vector2D location;
    protected Vector2D velocity;
    
    private int z;
    protected double health;
    protected double startHealth;

    private static final AffineTransform t = MathEx.getTransform();
    private static AffineTransform o;
    protected double rotation = 0;
    private boolean collisionsenabled = true;
    private boolean expired = false;
    private boolean visible = true;
    
    protected static EffectManager effects;
    protected static Raycaster rayCaster;
    protected static PathFinder pathFinder;

    /**
     * Create a new sprite that is currently stationary.
     * @param a
     * @param x
     * @param y
     */
    public Sprite(Animation[] anims,int animation,double x,double y,int z,double health){
	this.anims = anims;
        this.animation = anims[animation];
	location = new Vector2D(x,y);
        velocity = new Vector2D();
	this.z = z;
        this.startHealth = health;
	this.health = health;
    }

    //advance the sprite
    public void update(long elapsedTime) {
	//eliminate the sprite if it runs out of health
	if(health <= 0)expire();
	
	//advance the animation if this class uses one
	if(animation != null)
	    animation.update(elapsedTime);

        //move the sprite
        Vector2D.scratch.setTo(velocity);
        Vector2D.scratch.scale((double)elapsedTime);
	location.add(Vector2D.scratch);
    }

    /**
     * Draw the sprite.
     * @param g
     */
    public void draw(Graphics2D g,int drawx,int drawy,TileMap map) {
	
	if (!visible) {
	    return;
	}
	
        //draw the rotated image
        o = g.getTransform();
        t.setToIdentity();
        t.rotate(rotation + MathEx.halfPi,drawx + getWidth()/2,drawy + getHeight()/2);
        g.transform(t);
        g.drawImage(animation.getCurrent(),drawx,drawy,null);
        g.setTransform(o);
    }
    
    public abstract void rayHit(Sprite source);
    
    public abstract void collision(Sprite other);
    
    public void hit(double power){
	health -= power;
    }

    public double getX() {
        return location.x;
    }

    public double getY() {
        return location.y;
    }
    
    public double getHealth(){
	return health;
    }

    public Image getImage(){
	return animation.getCurrent();
    }

    public final int getWidth(){
	return animation.getWidth();
    }

    public final int getHeight() {
	return animation.getHeight();
    }
    
    public final double getWidthGrid(){
        return TileMap.pixelsToGridUnits(getWidth());
    }
    
    public final double getHeightGrid(){
        return TileMap.pixelsToGridUnits(getHeight());
    }
    
    public double centerX(){
	return location.x + getWidthGrid()/2;
    }
    
    public double centerY(){
	return location.y + getHeightGrid()/2;
    }

    public boolean isExpired() {
	return expired;
    }

    public void expire() {
	expired = true;
    }

    public boolean isVisible() {
	return visible;
    }

    public void setVisible(boolean b) {
	visible = b;
    }

    public boolean collisionsEnabled(){
	return collisionsenabled;
    }

    public void setCollisionsEnabled(boolean b){
	collisionsenabled = b;
    }
    
    public void setZ(int z){
	this.z = z;
    }
    
    public int getZ(){
	return z;
    }


    public void setAnimation(Animation a){
	animation = a;
    }
    
    public Vector2D getVelocity(){
        return velocity;
    }
    
    public Vector2D getLocation(){
        return location;
    }
    
    /**
     * Sets the direction that the sprite's
     * IMAGE is facing. NOTE: may also
     * affect behavior.
     */
    public void setRotation(double radians){
        this.rotation = radians;
    }
    
    public double getRotation(){
        return rotation;
    }
    
    protected void setGoal(double magnitude,double x,double y){
        velocity.setTo(x,y); //set to goal location
        
        Vector2D.scratch.setTo(centerX(),centerY());
        
        velocity.subtract(Vector2D.scratch);  //find vector between location and goal
        velocity.normalize();       //prepare to scale
        velocity.scale(magnitude);  //so that sprite will move at correct speed
        
        //face direction to move
        rotation = velocity.getAngle();
    }
    
    public boolean isOffScreen(int swidth,int sheight,int drawx,int drawy){
	return (drawx < -getWidth() || drawy < -getHeight() || drawx > swidth || drawy > sheight);
    }
    
    public boolean isInsideBounds(double x,double y){
	return (x >= getX() && x <= getX() + getWidthGrid() && y >= getY() && y <= getY() + getHeightGrid());
    }
    
    public Object clone(){
	try{
	    return super.clone();
	}catch(Exception e){
	    e.printStackTrace();
	}
	
	return null;
    }
    
    public static void setEffectManager(EffectManager e){
	effects = e;
    }
    
    public static void setPathFinder(PathFinder p){
	pathFinder = p;
    }
    
    public static void setRaycaster(Raycaster r){
	rayCaster = r;
    }
}
